package org.opens.service.impl;

import org.opens.constant.LockConstant;
import org.opens.dao.ProductMapper;
import org.opens.entity.ProductEntity;
import org.opens.service.ProductService;
import org.opens.util.RedisLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

/**
 * 功能:
 *
 * @author zym
 * @Date 2022/6/28 17:23
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private RedisLock redisLock;

    @Override
    @Transactional
    public boolean subStack1(Integer id) {
        synchronized (this) {
            ProductEntity productEntity = productMapper.selectById(id);
            if (productEntity == null) {
                throw new RuntimeException("对应商品不存在!");
            }

            if (productEntity.getStock() <= 0) {
                throw new RuntimeException("当前商品库存不足!");
            }

            // 模拟占锁
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            productEntity.setStock(productEntity.getStock() - 1);
            productMapper.updateById(productEntity);

            return true;
        }
    }

    @Override
    @Transactional
    public boolean subStack2(Integer id) {
        long startTime = System.currentTimeMillis();
        long timeOut = 5000L;
        // 超时时间小于代码执行时间将会导致锁失效, 所以应该设置一个较长的失效时间, 防止出现这种情况
        String token = redisLock.lock(LockConstant.PRODUCT_LOCK + id, timeOut);

        try {
            if (token == null) {
                return false;
            }
            ProductEntity productEntity = productMapper.selectById(id);
            if (productEntity == null) {
                throw new RuntimeException("对应商品不存在!");
            }

            if (productEntity.getStock() <= 0) {
                throw new RuntimeException("当前商品库存不足!");
            }

            // 模拟占锁
            Thread.sleep(2000);

            productEntity.setStock(productEntity.getStock() - 1);
            productMapper.updateById(productEntity);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            if (token != null) {
                redisLock.unlock(LockConstant.PRODUCT_LOCK + id, token);
            }
        }

        redisLock.checkRuntime(startTime, timeOut);

        return true;
    }

}
